package org.apache.dolphinscheduler.api.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.UserGroupService;
import org.apache.dolphinscheduler.api.service.UserGroupWorkerService;
import org.apache.dolphinscheduler.api.service.UsersService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.entity.UserGroup;
import org.apache.dolphinscheduler.dao.mapper.UserGroupMapper;
import org.apache.dolphinscheduler.dao.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserGroupServiceImpl extends ServiceImpl<UserGroupMapper, UserGroup> implements UserGroupService {
	
	@Autowired
	private UserGroupWorkerService userGroupWorkerService;
	@Autowired
	private UsersService usersService;
	@Autowired
	private UserMapper userMapper;

	public Result queryAllGroupPaging(User loginUser, Integer pageNo, Integer pageSize, String searchVal) {
		Result<Object> result = new Result<>();
//        if (loginUser.getRoleId() != null && loginUser.getRoleId().intValue() != 1) {
//            log.warn("User does not have permission for this feature, userId:{}, userName:{}.", loginUser.getId(),
//                    loginUser.getUserName());
//            result.setCode(Status.USER_NO_OPERATION_PERM.getCode());
//        	result.setMsg(Status.USER_NO_OPERATION_PERM.getMsg());
//            return result;
//        }
		QueryWrapper<UserGroup> qw = new QueryWrapper<UserGroup>();
		if(StringUtils.isNotBlank(searchVal)) {
			qw.like("user_group_name", "%" + searchVal +"%");
		}
		qw.orderByDesc("create_time");
		Page<UserGroup> page = new Page<>(pageNo, pageSize);
		page = page(page, qw);
		if(page.getRecords() != null && page.getRecords().size() > 0) {
			for(UserGroup ug : page.getRecords()) {
				ug.setUserGroupWork(userGroupWorkerService.queryByGroupId(ug.getId()));
				ug.setGroupAdminName(usersService.queryUserNameByIds(ug.getGroupAdmin()));
				Long count = countByUserAuditStatus(ug.getId());
				if(count > 0) {
					ug.setIsHighlight(true);
				} else {
					ug.setIsHighlight(false);
				}
			}
		}
		PageInfo<UserGroup> pageInfo = new PageInfo<>(pageNo, pageSize);
        pageInfo.setTotal((int) page.getTotal());
        pageInfo.setTotalList(page.getRecords());
        result.setData(pageInfo);
        
        result.setCode(Status.SUCCESS.getCode());
    	result.setMsg(Status.SUCCESS.getMsg());
        return result;
	}
	
	public Map<String, Object> saveUserGroup(User loginUser, UserGroup userGroup) {
		Map<String, Object> result = new HashMap<>();
        if (loginUser.getRoleId() != null && loginUser.getRoleId().intValue() != 1) {
        	result.put(Constants.STATUS,Status.USER_NO_OPERATION_PERM);
        	result.put(Constants.MSG,Status.USER_NO_OPERATION_PERM.getMsg());
            return result;
        }
        if (StringUtils.isEmpty(userGroup.getUserGroupName())) {
            log.warn("Parameter name can ot be null.");
            result.put(Constants.STATUS,Status.NAME_NULL);
        	result.put(Constants.MSG,Status.NAME_NULL.getMsg());
            return result;
        }
        long count = queryUserGroupCount(userGroup.getUserGroupName());
        if(userGroup.getId() != null && userGroup.getId() != 0) {
        	UserGroup ug = getById(userGroup.getId());
        	if(!ug.getUserGroupName().equals(userGroup.getUserGroupName()) && count > 0) {
        		log.warn("Worker group with the same name already exists, name:{}.", userGroup.getUserGroupName());
            	result.put(Constants.STATUS,Status.NAME_EXIST);
            	result.put(Constants.MSG, MessageFormat.format(Status.NAME_EXIST.getMsg(), userGroup.getUserGroupName()));
                return result;
        	}
        } else if(userGroup.getId() == null && count > 0) {
        	log.warn("Worker group with the same name already exists, name:{}.", userGroup.getUserGroupName());
        	result.put(Constants.STATUS,Status.NAME_EXIST);
        	result.put(Constants.MSG, MessageFormat.format(Status.NAME_EXIST.getMsg(), userGroup.getUserGroupName()));
            return result;
        }
        
        saveOrUpdate(userGroup);
        
        if(userGroup.getWorkIds() != null && userGroup.getWorkIds().size() > 0) {
        	userGroupWorkerService.saveUserGroupWork(userGroup.getId(), userGroup.getWorkIds());
        }
        
        result.put(Constants.STATUS,Status.SUCCESS);
    	result.put(Constants.MSG,Status.SUCCESS.getMsg());
        return result;
	}
	
	public Map<String, Object> deleteUserGroupById(User loginUser, Integer id) {
		Map<String, Object> result = new HashMap<>();
        if (loginUser.getRoleId() != null && loginUser.getRoleId().intValue() != 1) {
        	result.put(Constants.STATUS,Status.USER_NO_OPERATION_PERM);
        	result.put(Constants.MSG,Status.USER_NO_OPERATION_PERM.getMsg());
            return result;
        }
        Long count = usersService.countByUserGroupId(id);
        if(count > 0) {
        	result.put(Constants.STATUS,Status.DELETE_GROUP_USER_EXIST);
        	result.put(Constants.MSG,Status.DELETE_GROUP_USER_EXIST.getMsg());
            return result;
        }
        userGroupWorkerService.deleteByGroupId(id);
        removeById(id);
        result.put(Constants.STATUS,Status.SUCCESS);
    	result.put(Constants.MSG,Status.SUCCESS.getMsg());
        return result;
	}

	/**
	 * 查询用户是管理员的所有用户组下的用户*
	 * @param loginUser
	 * @return
	 */
	@Override
	public List<Integer> queryAllUserByGroupAdmin(User loginUser) {
		LambdaQueryWrapper<UserGroup> lqw = Wrappers.lambdaQuery();
		lqw.apply("FIND_IN_SET({0}, group_admin)", loginUser.getId());
		List<UserGroup> list = this.list(lqw);
		if (!CollectionUtils.isEmpty(list)) {
			List<Integer> userGroupIdList = list.stream().map(UserGroup::getId).collect(Collectors.toList());
			LambdaQueryWrapper<User> lqwUser = Wrappers.lambdaQuery();
			lqwUser.in(User::getUserGroupId, userGroupIdList);
			List<User> users = userMapper.selectList(lqwUser);
			if (!CollectionUtils.isEmpty(users)) {
				return users.stream().map(User::getId).collect(Collectors.toList());
			}
		}
		return null;
	}
	
	private Long countByUserAuditStatus(Integer userGroupId) {
		QueryWrapper<User> qw = new QueryWrapper<User>();
		qw.eq("user_group_id", userGroupId);
		qw.and(warrper -> warrper.eq("audit_status", 3).or().eq("enterprise_audit_status", 3));
		
		return userMapper.selectCount(qw);
	}

	@Override
	public List<Integer> queryAllGroupByGroupAdmin(User loginUser) {
		LambdaQueryWrapper<UserGroup> lqw = Wrappers.lambdaQuery();
		lqw.apply("FIND_IN_SET({0}, group_admin)", loginUser.getId());
		List<UserGroup> list = this.list(lqw);
		if (!CollectionUtils.isEmpty(list)) {
			return list.stream().map(UserGroup::getId).collect(Collectors.toList());
		}
		return null;
	}

	private long queryUserGroupCount(String userGroupName) {
		QueryWrapper<UserGroup> qw = new QueryWrapper<UserGroup>();
		qw.eq("user_group_name", userGroupName);
		return count(qw);
	}
	
}
